简介
Rafy 领域服务是跨组合实体的业务逻辑的封装体。一个领域服务协同一系列领域实体来完成一个独立的业务逻辑。
由于领域服务使用了命令模式,相对于领域控制器,领域服务是更加细粒度的逻辑封装。一般情况下,还建议开发者使用领域控制器即可。
Rafy 领域服务的特点:
- 领域逻辑封装体 Rafy 中的服务与经典 DDD 中的领域服务类似,它们都是业务逻辑的封装体、组织体。
- 采用命令模式设计 与其它的服务框架不同,Rafy 使用了命令模式来设计领域服务,以单独类来封装每个单独的服务。而 WebService/WCF 等服务框架,则是用方法来表达每一个单独的服务。把服务抽象为单独的类的模式,不但可以保证服务与服务间的相互独立,还能更好地使用面向对象的特性来提供服务的可扩展性。
- 较高的可扩展性 服务的可替换性:通过服务的工厂来创建服务的实例,使得我们对服务的创建过程进行扩展。例如可以使用新的服务来替换旧的服务,而不需要修改旧的服务调用代码。
- 无状态 领域服务是无状态的。虽然服务类都有属性,但每一次服务的调用都需要构造新的服务对象,而服务对象的属性只是为了传递服务的输入和输出,是临时的状态,当调用完成后,服务对象即被丢弃、回收。
- 支持本地调用,也支持分布式调用 领域服务也是除了仓库查询以外,提供分布式数据传输的另一机制。服务的调用,支持本地调用,也支持分布式调用。详见:部署。
- SOA 架构的基础 在面向服务架构思想的指导下,Rafy 才抽取出领域服务。同时领域服务也是在 Rafy 框架中进行多系统集成的基础组件。
代码示例
以下代码声明了一个简单的加法逻辑服务:
[Serializable, Contract, ContractImpl]
public class AddService : Service
{
//服务的两个输入参数
public int A { get; set; }
public int B { get; set; }
//服务的输出参数
[ServiceOutput]
public int Result { get; set; }
protected override void Execute()
{
Result = A + B;
}
}
要支持远程调用,必须标记服务为可序列化的。
对服务的调用也很简单,直接通过服务工厂服务一个服务对象,设置输入参数,调用服务,即可获取服务的输出:
AddService svc = ServiceFactory.Create<AddService>();
svc.A = 1;
svc.B = 2;
svc.Invoke();//自动分辨为远程调用,还是本地调用。
int result = svc.Result;
服务的输入与输出
以类的形式封装服务后,同样,每个服务需要声明它的输出和输出,形同方法的参数与返回值。领域服务的输入和输出都以服务类的属性的形式编写。例如上面 AddService 中的 A、B 两个属性是输出属性,而 Result 属性则是输出属性。
- 输出属性
标记了ServiceOutputAttribute
特性的属性都是服务的输出。
注意,一个服务可以有多个输出。 - 输入属性
没有任何标记、或者标记了ServiceInputAttribute
特性的属性都是服务的输入。
一个属性可以即是输入也是输出,这时需要同时标记以上两个特性。
服务的扩展
在低启动级别的插件中,可以使用 ServiceFactory.Override 方法来替换高启动级别插件中的指定服务。这样,使用工厂创建出的服务,都是替换后的服务。
SOA
由于使用了单独的类来封装每一个服务,可使用反射更方便地遍历出所有的服务,所以更便于对服务进行管理。框架提供了 API 来完成查询服务、替换服务等功能。